package edu.neu.cs6515.test.runner;

import java.util.List;

import com.google.common.collect.ImmutableList;

import edu.neu.cs6515.board.rules.Rule;
import edu.neu.cs6515.turn.AbstractTurnProxy;
import edu.neu.cs6515.turn.ITurnProxy;
import edu.neu.cs6515.turn.TurnProxy;
import edu.neu.cs6515.xml.Bad;
import edu.neu.cs6515.xml.False;
import edu.neu.cs6515.xml.Placement;
import edu.neu.cs6515.xml.Player;
import edu.neu.cs6515.xml.Tile;
import edu.neu.cs6515.xml.XMLTurnProxy;

/**
 * Testrunner for integration-tests of the Turn
 */
public class TurnTestRunner extends AbstractTestRunner {

    private boolean acceptNewTurnsOnBoard = true;
    private XMLTurnProxy currentTurn;
    private XMLTurnProxy.Player xmlplayer;
    private List<Tile> tilesToBeHandedByAdmin;

    /**
     * C'tor, executes turn immediately
     * 
     * @param currentTurn
     *            turn to be executed
     */
    public TurnTestRunner(final XMLTurnProxy currentTurn) {
        super(currentTurn.getBoard());
        this.currentTurn = currentTurn;
        xmlplayer = currentTurn.getPlayer();
        tilesToBeHandedByAdmin = currentTurn.getAdministrator().getTile();
        executeTurn();
    }

    @Override
    protected void initializePlacements(final List<Placement> placements) {
        for (final Placement placement : placements) {
            List<Rule> brokenRules = board.getBrokenRules(placement);
            if (brokenRules.size() > 0) {
                gameResults.setBad(ImmutableList.of(new Bad(brokenRules.get(0)
                        .getReason())));
                acceptNewTurnsOnBoard = false;
                return;
            } else {
                board.updateHexagonBoard(placement);
            }
        }
    }

    /**
     * Executes a complete turn and updates the gameResults accordingly
     */
    public void executeTurn() {
        if (acceptNewTurnsOnBoard) {
            List<Placement> placements = currentTurn.getActions().getPlacement();

            ITurnProxy proxy = new TurnProxy(board, xmlplayer.getTile(),
                    xmlplayer.getScore(), tilesToBeHandedByAdmin);
            for (Placement placement : placements) {
                if (!placeTileViaProxy(proxy, placement)) {
                    break;
                }
            }

            if (proxy.getRequiredPlacements() > 0 && gameResults.getBad().isEmpty()) {
                gameResults.getBad().add(new Bad(AbstractTurnProxy.TURN_NOT_FINISHED));
            }
        }
    }

    /**
     * Attempt to place the given tile on the board (via proxy)
     * 
     * @param proxy
     *            used proxy for placement attempt
     * @param placement
     *            placement to attempt
     * @return true if the placement was successful
     */
    private boolean placeTileViaProxy(final ITurnProxy proxy,
            final Placement placement) {
        List<String> brokenRules = proxy.getErrorsInPlacement(placement);
        if (brokenRules.isEmpty()) {
            List<Tile> newTile = proxy.placeTile(placement);
            if (newTile.isEmpty()) {
                gameResults.getFailList().add(new False());
            } else {
                gameResults.getTile().add(newTile.get(0));
            }
            return true;
        } else {
            gameResults.getBad().add(new Bad(brokenRules.get(0)));
            return false;
        }
    }
}
